/* CIRCULAR BUFFER QUEUE */

#include "kernel.h" 
#define NULL 0

//create a new queue
struct queue_str* queue_init(struct queue_str* q){
		q = malloc(sizeof(*q));
		printf_m("queue address %x \n", q);
		q->size = 0;
		q->head = q->tail = NULL;
		printf_m("A new queue has been initalized");
		return q;
 }
 
//adds a packet to the queue
void enqueue_packet(struct honeypot_command_packet *command_loc, struct queue_str *q, unsigned int length){
	
	//find the size of the data
	int data_size = length - sizeof(command_loc);
	int size = length;
	
	struct node_packet* pack;
	pack = (struct node_packet*) malloc(sizeof(struct node_packet) + data_size*sizeof(char));
	
	//Allocate all of the packet
	pack->pkt.headers = command_loc->headers;
	pack->pkt.secret_big_endian = command_loc->secret_big_endian;
	pack->pkt.data_big_endian = command_loc->data_big_endian;
	pack->pkt.cmd_big_endian = command_loc->cmd_big_endian;
	pack->length = length;
	pack->processed = 0;
	pack->initialized = 1;
	pack->next = NULL;
	pack->previous = NULL;
	
	char* data_ref = (char *) &(command_loc->data);
	
	// Copy the data from the buffer to the new packet
	for(int i = 0; i < data_size; i++){
		pack->pkt.data[i] = (char) data_ref[i];
	}
	
	
	if( q->head == NULL){
		// If this is the first element in the queue, add it and set pointers
		q->head = q->tail = pack;
		pack->next = q->tail;
		pack->previous = q->tail;	
	}
	else{
		// Add an additonal element to the queue and move pointers accordingly
		q->tail->next = pack;
		pack->previous = q->tail;
		pack->next = q->head;
		q->tail = pack;
		q->head->previous = pack;
	}
	
	q->size++;
}

struct node_packet* dequeue_packet(struct queue_str *q){
	//create the return packet and find its address
	struct node_packet *node = NULL;
	
	//Remove the node from the queue 
	if(q->size != 0){
		// Check if the queue has an elements 
		node = q->head;
		if(--(q->size)){
			// If the queue has more than 1 node
			q->head = q->head->next;
			q->head->previous = q->tail;
			q->tail->next = q->head;
		}else{
			// If a one node queue
			q->head = q->tail = NULL;
		}
	}
	
	return node;
}

void enqueue_lock_packet(struct honeypot_command_packet *command_loc, struct queue_str *q, unsigned int length, int* queue_lock){
	// mutex protected call to enqueue
	mutex_lock(queue_lock);
	enqueue_packet(command_loc,q,length);
	mutex_unlock(queue_lock);
}

struct node_packet* dequeue_lock_packet(struct queue_str *q, int* queue_lock){
	// mutex protected call to dequeue
	struct node_packet* temp;
	mutex_lock(queue_lock);
	temp = dequeue_packet(q);
	mutex_unlock(queue_lock);
	return temp;
}
